package com.wxy.ideaplugin.generator;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.wxy.ideaplugin.utils.SwitchLineCamel;

import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * @author wuxiaoyong
 * @version 1.0.1
 * mybatis-plus 动态生成器
 */
public class MpGeneratorThread extends Thread{
    private String outputVueDirProj;
    private String outputDirProj;
    private String contextPath; //flow
    private String module; //shop
    private String domain; //order
    private String domainFirstUpper;
    private String domainFirstLower;

    private String outputDirView;
    private String outputDirRouter;
    private String outputDirMain;
    private String javaDir;
    private String packagePathParent;
    private String stripPrefix;

    private String packagePath;
    private String packagePathDot;
    private String dtoOutputDir;
    private String testOutputDir;
    private String mapperXmlOutputDir;
    private String dozerOutputDir;
    private String pgOutputDir;
    private JTextArea execlog_textArea;

    private Map<String, String> resourceMap;
    private Map<String, String> tableNameZh_tableNameMap;
    private Map<String, String> tableNameZh_domainMap = new HashMap<>();

    private JScrollBar scrollBar;
    private String projectPath;

    public MpGeneratorThread(Map<String, String> resourceMap, JTextArea execlog_textArea, Map<String, String> tableNameZh_tableNameMap, String projectPath) {
        this.resourceMap = resourceMap;
        this.execlog_textArea = execlog_textArea;
        this.tableNameZh_tableNameMap = tableNameZh_tableNameMap;
        this.projectPath = projectPath;
        //滚动尾部
        JScrollPane scrollPane1 = (JScrollPane)execlog_textArea.getParent().getParent();
        this.scrollBar=scrollPane1.getVerticalScrollBar();
    }

    public void run() {
        execlog_textArea.append("#-------源码生成开始---------;\n");

        try {
            String tablePrefix = resourceMap.get("tablePrefix");
            String groupMenuJsonStr = resourceMap.get("groupMenuJsonStr");
            JSONObject groupMenuJson = JSONObject.parseObject(groupMenuJsonStr);

            StringBuilder tableNameSB = new StringBuilder();
            for (String groupName : groupMenuJson.keySet()) {
                //二级菜单 如：key = 用户管理
                String domain = "";
                String tableNames = "";
                tableNameSB.setLength(0);
                JSONArray tableNameZhList = groupMenuJson.getJSONArray(groupName); //["用户", "用户地址", "用户购物车", "用户订单"]
                execlog_textArea.append("#-- groupName:");
                execlog_textArea.append(groupName);
                execlog_textArea.append(" --;\n");
                for (int i = 0; i < tableNameZhList.size(); i++) {
                    String tableNameZh = (String) tableNameZhList.get(i);
                    String tableName = tableNameZh_tableNameMap.get(tableNameZh);
                    String tableName_noPrefix = "";
                    if (tableName.startsWith(tablePrefix)) {
                        tableName_noPrefix = tableName.replaceFirst(tablePrefix, "");
                    }
                    //第一个表名,前部分作为domain
                    if (i == 0) {
                        if (tableName_noPrefix.contains("_")) {
                            String t1 = tableName_noPrefix.substring(0, tableName_noPrefix.lastIndexOf("_"));
                            String domainProperty = SwitchLineCamel.switch2Property(t1);
                            domain = domainProperty.substring(0, 1).toLowerCase() + domainProperty.substring(1);
                        } else {
                            String domainProperty = SwitchLineCamel.switch2Property(tableName_noPrefix);
                            domain = domainProperty.substring(0, 1).toLowerCase() + domainProperty.substring(1);
                        }
                    }
                    tableNameSB.append(tableName).append(",");
                    tableNameZh_domainMap.put(tableNameZh, domain);
                    execlog_textArea.append("# ");
                    execlog_textArea.append(tableNameZh);
                    execlog_textArea.append(" ;\n");
                    //滚动尾部
                    scrollBar.setValue(scrollBar.getMaximum());
                }
                tableNameSB.deleteCharAt(tableNameSB.length() - 1);
                tableNames = tableNameSB.toString();
                resourceMap.put("tables", tableNames);
                resourceMap.put("tablePrefix", tablePrefix);
                resourceMap.put("domain", domain);
                //
                execute();
                //滚动尾部
                execlog_textArea.append("#-- group end --;\n");
                scrollBar.setValue(scrollBar.getMaximum());
            }
            //滚动尾部
            Thread.sleep(100);
            execlog_textArea.append("#-------源码生成完成---------;\n\n\n");
            scrollBar.setValue(scrollBar.getMaximum());
        }catch (Exception e) {
            e.printStackTrace();
        }

    }


    private void initPath(){
        this.outputDirProj = resourceMap.get("outputDirProj");
        this.javaDir = resourceMap.get("javaDir");
        this.packagePath = resourceMap.get("packagePath");
        this.packagePathDot = this.packagePath.replaceFirst("/",""); //   /com/wxy/ej/flow/modules  -> com.wxy.ej.flow.modules
        this.packagePathDot = this.packagePathDot.replaceAll("/",".");
        this.contextPath = resourceMap.get("contextPath");
        this.module = resourceMap.get("module");
        this.domain = resourceMap.get("domain");
        this.outputVueDirProj = resourceMap.get("outputVueDirProj");
        outputDirMain = outputDirProj+File.separator+this.javaDir+File.separator+this.packagePath+File.separator+module+File.separator+domain+File.separator;
        outputDirView =  outputVueDirProj+File.separator+"src"+File.separator+"views"+File.separator+"coding"+File.separator+contextPath+File.separator+module+File.separator+domain;
        outputDirRouter =  outputVueDirProj+File.separator+"router"+File.separator+"coding";
        pgOutputDir = outputDirMain ;
        dtoOutputDir = pgOutputDir + "/dto/";
        testOutputDir = pgOutputDir + "/service/test/";
        mapperXmlOutputDir = outputDirProj+File.separator + "src/main/resources/mapper/"+module+"/"+domain+"/";
        dozerOutputDir = outputDirMain + "/resources/dozer/"+domain+"/";
    }


    public void execute() throws IOException {
        //init path
        initPath();
        //jdbc
        String jdbcDriver = resourceMap.get("jdbcDriver");
        String jdbcUrl = resourceMap.get("jdbcUrl");
        String username = resourceMap.get("username");
        String password = resourceMap.get("password");
        //
        String[] tables = resourceMap.get("tables").split(",");
        String tablePrefix = resourceMap.get("tablePrefix");

        execlog_textArea.append("# 表名：;\n");
        for (int i=0;i<tables.length;i++) {
            String tableName = tables[i];
            execlog_textArea.append("# "+tableName+";\n");
            //滚动尾部
            scrollBar.setValue(scrollBar.getMaximum());
        }

        AutoGenerator mpg = new AutoGenerator();
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setOutputDir(outputDirMain + javaDir);
        gc.setFileOverride(true);
        gc.setActiveRecord(true);// 开启 activeRecord 模式
        gc.setEnableCache(false);// XML 二级缓存
        gc.setBaseResultMap(true);// XML ResultMap
        gc.setBaseColumnList(true);// XML columList
        gc.setDateType(DateType.ONLY_DATE);
        // 此处设置生成人名字
        gc.setAuthor("wuxiaoyong");
        // 自定义文件命名，注意 %s 会自动填充表实体属性！
        gc.setMapperName("%sBaseMapper" );
        gc.setXmlName("%sBaseMapper" );
        gc.setServiceName("%sBaseService" );
        gc.setServiceImplName("%sBaseServiceImpl" );
        gc.setControllerName("%sBaseController" );
        gc.setSwagger2(false);
        mpg.setGlobalConfig(gc);
        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setDbType(DbType.MARIADB);
        dsc.setTypeConvert(new MySqlTypeConvert());
        dsc.setDriverName(jdbcDriver);
        dsc.setUrl(jdbcUrl);
        dsc.setUsername(username);
        dsc.setPassword(password);
        mpg.setDataSource(dsc);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        //strategy.setTablePrefix(new String[] {"tw1_"});// 此处可以修改为您的表前缀
        strategy.setTablePrefix(tablePrefix);// 此处可以修改为您的表前缀
        //strategy.setInclude(new String[]{"tw1_supplier"}); // 需要生成的表
        strategy.setInclude(tables); // 需要生成的表
        strategy.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略
        mpg.setStrategy(strategy);

        gen(gc, mpg);
    }


    /**
     * https://blog.csdn.net/weixin_45511500/article/details/118370669
     */
    private void gen(GlobalConfig gc, AutoGenerator mpg) throws IOException {
        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(null);  //所属模块
        //pc.setParent("com.wxy.ej.flow.modules."+module+"."+domain);// 自定义包路径
        pc.setParent(this.packagePathDot+"."+module+"."+domain);// 自定义包路径
        pc.setController("controller");
        pc.setEntity("bean" );
        pc.setXml("mapper" );
        pc.setMapper("repository.mapper" );
        pc.setService("service.beanService" );
        mpg.setPackageInfo(pc);

        //
        TemplateConfig tc = new TemplateConfig();
        tc.setXml(null);
        tc.setEntity(null);
        tc.setController(null);
        tc.setMapper(null);
        tc.setService(null);
        tc.setServiceImpl(null);
        mpg.setTemplate(tc);
        //
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        Map<String, Object> map = new HashMap<>();
        //map.put("package_base_name", "com.wxy.ej.flow.modules."+module+"."+domain);
        map.put("package_base_name", this.packagePathDot+"."+module+"."+domain);
        map.put("package_name", pc.getParent());
        map.put("package_mvc_path", "/coding/");
        map.put("package_superMapperClassPackage", "com.rt.utils.base");
        map.put("contextPath", contextPath);
        map.put("module", module);
        map.put("domain", domain);
        map.put("domainFirstUpper", domainFirstUpper);
        map.put("domainFirstLower", domainFirstLower);
        map.put("isTreeTable", false);
        map.put("classNameFirstWordLower", "classNameFirstWordLower");//????????

        // 注入自定义配置，可以在 VM 中使用 cfg.abc 设置的值
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                this.setMap(map);
            }
        };

        List<FileOutConfig> focList = new ArrayList<>();
        Set<String> outFileFullPathList = new HashSet<>();
        MpFileWriter genFileWriter = new MpFileWriter(focList, outFileFullPathList);

        genVue(genFileWriter, null);
        genTmptExtend(genFileWriter);

        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 执行生成
        mpg.execute();
    }


    private void genTmptExtend(MpFileWriter genFileWriter){
        String basePath = "";//projectPath+"aicode";
        genFileWriter.write(basePath+"/template/biz/dto.java.ftl",
                pgOutputDir+File.separator+"dto", "%sDto.java");
        genFileWriter.write(basePath+"/template/biz/entity.java.ftl",
                pgOutputDir+File.separator+"bean", "%s.java");
        genFileWriter.write(basePath+"/template/biz/mapper.java.ftl",
                pgOutputDir+File.separator+"mapper", "%sMapper.java");
        // mapper struct
        genFileWriter.write(basePath+"/template/biz/dtomapper.java.ftl",
                pgOutputDir+File.separator+"dtomapper", "%sDtoMapper.java");
        genFileWriter.write(basePath+"/template/biz/service.java.ftl",
                pgOutputDir+File.separator+"service", "%sService.java");
        genFileWriter.write(basePath+"/template/biz/controller.java.ftl",
                pgOutputDir+File.separator+"controller", "%sController.java");
        genFileWriter.write(basePath+"/template/biz/mapper.xml.ftl",
                mapperXmlOutputDir, "%sMapper.xml");
        // modules
        /*if(!FileUtils.isExist(pgOutputDir+File.separator+"facade"+File.separator+domainFirstUpper+"Facade.java")){
            genFileWriter.write("/template/biz/facade.java.ftl",
                    pgOutputDir + File.separator + "facade", domainFirstUpper + "Facade.java");
        }
        if(!FileUtils.isExist(pgOutputDir + File.separator + "repository"+File.separator+domainFirstUpper+"Repository.java")) {
            genFileWriter.write("/template/biz/repository.java.ftl",
                    pgOutputDir + File.separator + "repository", domainFirstUpper + "Repository.java");
        }
        */
    }


    private void genVue(MpFileWriter genFileWriter, String appendPath){
        //String basePath = projectPath+"aicode";
        String basePath = "";//projectPath+"aicode";
        genFileWriter.write(basePath+"/template/vue/list.vue.ftl",
                outputDirView, true, "list.vue", appendPath);
        genFileWriter.write(basePath+"/template/vue/form-details.vue.ftl",
                outputDirView, true, "form-details.vue", appendPath);
        genFileWriter.write(basePath+"/template/vue/form-add.vue.ftl",
                outputDirView, true, "form-add.vue", appendPath);
        genFileWriter.write(basePath+"/template/vue/api.js.ftl",
                outputDirView, true, "api.js", appendPath);
        genFileWriter.write(basePath+"/template/vue/data.js.ftl",
                outputDirView, true, "data.js", appendPath);
        genFileWriter.write(basePath+"/template/vue/index.vue.ftl",
                outputDirView, true, "index.vue", appendPath);
        /*genFileWriter.write("/template/vue/list-line-edit.vue.ftl",
                outputDirView, true, "list-line-edit.vue", appendPath);
        genFileWriter.write("/template/vue/complex-list.vue.ftl",
                outputDirView, true, "complex-list.vue", appendPath);
        genFileWriter.write("/template/vue/complex-list-line-edit.vue.ftl",
                outputDirView, true, "complex-list-line-edit.vue", appendPath);
        genFileWriter.write("/template/vue/aside-calendar.vue.ftl",
                outputDirView, true, "aside-calendar.vue", appendPath);*/

        // 树结构
        /*if ((Boolean)map.get("isTreeTable") == true) {
            genFileWriter.write("/template/vue/tree.vue.ftl",
                    outputDirView, true, "tree.vue", appendPath);
            genFileWriter.write("/template/vue/tree-table.vue.ftl",
                    outputDirView, true, "tree-table.vue", appendPath);
        }
        // AsideTree结构
        if ((Boolean)map.get("hasAsideTree") == true) {
            genFileWriter.write("/template/vue/aside-tree.vue.ftl",
                    outputDirView, true, "aside-tree.vue", appendPath);
        }*/
    }


}
